/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2007 The OGRE Team
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.
-----------------------------------------------------------------------------
*/

/*
-----------------------------------------------------------------------------
Filename:    WallSpiral.h
Description: A place for me to try out stuff with OGRE.
-----------------------------------------------------------------------------
*/
#ifndef __WallSpiral_h_
#define __WallSpiral_h_


#include "ExampleApplication.h"
#include "Wall3D.h"
#include "Wall3DStrip.h"

typedef Ogre::Vector3 OgreVec3;

class WallSpiralFrameListener : public ExampleFrameListener
{
private:
   SceneManager* mSceneMgr;
public:
      WallSpiralFrameListener(SceneManager *sceneMgr, RenderWindow* win, Camera* cam)
         : ExampleFrameListener(win, cam),
         mSceneMgr(sceneMgr)
	{
	}

	bool frameStarted(const FrameEvent& evt)
	{
		bool ret = ExampleFrameListener::frameStarted(evt);
		return ret;
	}
};


//------------------------------------------------------------------------
//	
//
//------------------------------------------------------------------------
class WallSpiralApp : public ExampleApplication
{
public:
	
	WallSpiralApp()
    {}

	~WallSpiralApp()
	{
	}

protected:

	virtual void createCamera(void)
	{
		// Create the camera
		mCamera = mSceneMgr->createCamera("PlayerCam");
		// Position it at 500 in Z direction
		mCamera->setPosition(Ogre::Vector3(0,170,-250));
		// Look back along -Z
		mCamera->lookAt(Ogre::Vector3(0,10,0));
		mCamera->setNearClipDistance(1);
	}




	// Just override the mandatory create scene method
	virtual void createScene(void)
	{
		

		//////////////////////////////////////////////////////////////////////////
		// TEST
		/*Wall3D wall(MyVec3(-10,0,0),MyVec3(10,0,0),20.0);
		createWallMesh2(wall,"mywall");

		Entity* wallEnt = mSceneMgr->createEntity("thewall","mywall");
		wallEnt->setMaterialName("Examples/Rockwall");
		wallEnt->setCastShadows(true);
		mSceneMgr->getRootSceneNode()->createChildSceneNode(OgreVec3(0,0,-20))->attachObject(wallEnt);*/

		/*createCube();
		Entity* thisEntity = mSceneMgr->createEntity("cc", "ColourCube");
		thisEntity->setMaterialName("Examples/Rockwall");
		SceneNode* thisSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
		thisSceneNode->setPosition(-35, 0, 0);
		thisSceneNode->attachObject(thisEntity);*/

		Wall3DStrip wallstrip(20);
		float ratio = -1.1f;
		int x=-20,z=20;
		for(int i=0; i<50; i++)
		{
			wallstrip.AddPoint(MyVec3(x,0,z));
			if (i%2==0)
				x *= ratio;
			else
				z *= ratio;
		}
		/*wallstrip.AddPoint(MyVec3(-20,0,20));
		wallstrip.AddPoint(MyVec3( 20,0,20));
		wallstrip.AddPoint(MyVec3( 5,0,-10));
		wallstrip.AddPoint(MyVec3( -10,0,-10));
		wallstrip.AddPoint(MyVec3( -10,0,20));
		wallstrip.AddPoint(MyVec3( 30,0,20));
		wallstrip.AddPoint(MyVec3( 30,0,-40));*/

		createWallStripMesh(wallstrip,"wallstripmesh",20);
		Entity* wallstripEnt = mSceneMgr->createEntity("thewallstrip","wallstripmesh");
		wallstripEnt->setMaterialName("Examples/Rockwall");
		wallstripEnt->setCastShadows(true);
		mSceneMgr->getRootSceneNode()->createChildSceneNode(OgreVec3(0,0,0))->attachObject(wallstripEnt);

		createSphere("mySphereMesh", 10, 64, 64);
		Entity* sphereEntity = mSceneMgr->createEntity("mySphereEntity", "mySphereMesh");
		SceneNode* sphereNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
		sphereEntity->setMaterialName("Examples/EnvMappedRustySteel");
		sphereNode->attachObject(sphereEntity);

		//END TEST
		//////////////////////////////////////////////////////////////////////////


		Ogre::Plane floor;
		floor.normal = OgreVec3::UNIT_Y;
		floor.d = 100;
		MeshManager::getSingleton().createPlane("Floor",
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,floor,
			1500,1500,20,20,true,1,60,60,OgreVec3::UNIT_Z);
		Entity* floorEnt = mSceneMgr->createEntity("FloorEnt","Floor");
		floorEnt->setMaterialName("Examples/Rocky");
		floorEnt->setCastShadows(false);
		mSceneMgr->getRootSceneNode()->createChildSceneNode(OgreVec3(0,99,0))->attachObject(floorEnt);

		// Set ambient light
		mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

		// Create a light
		Light* l = mSceneMgr->createLight("MainLight");
		l->setPosition(20,80,50);
	}

	// Create new frame listener
	void createFrameListener(void)
	{
		mFrameListener= new WallSpiralFrameListener(mSceneMgr, mWindow, mCamera);
		mRoot->addFrameListener(mFrameListener);
	}

	/** create a manual mesh for a given wall
	
	*/
	void createWallMesh(const Wall3D& wall,String strName)
	{
		MyVec3 a( (wall.From()) );
		MyVec3 b( (wall.To()) );
		MyVec3 n( (wall.Normal()) );
		const size_t nVertices = 4;
		const size_t vbufCount = (3*2+2)*nVertices;
		float vertices[vbufCount] = 
		{
			a[0],a[1],a[2], n[0], n[1], n[2], 0, 0,
			b[0],b[1],b[2], n[0], n[1], n[2], 1, 0,
			b[0],b[1]+wall.Height(),b[2], n[0], n[1], n[2], 1, 1,
			a[0],a[1]+wall.Height(),a[2], n[0], n[1], n[2], 0, 1
		};

		// define 2 triangles
		const size_t ibufCount = 12;
		unsigned short faces[ibufCount] = 
		{
			0,1,2,
			0,2,3,
			1,0,3,
			1,3,2
		};

		MeshPtr wallmesh = MeshManager::getSingleton().createManual(strName,
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		SubMesh *pWallVertex = wallmesh->createSubMesh();

		wallmesh->sharedVertexData = new VertexData();
		VertexData* vertexData = wallmesh->sharedVertexData;

		// define the vertex format
		VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
		size_t currOffset = 0;
		// positions
		vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION);
		currOffset += VertexElement::getTypeSize(VET_FLOAT3);
		// normals
		vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL);
		currOffset += VertexElement::getTypeSize(VET_FLOAT3);
		// two dimensional texture coordinates
		vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
		currOffset += VertexElement::getTypeSize(VET_FLOAT2);

		// allocate the vertex buffer
		vertexData->vertexCount = 4;
		HardwareVertexBufferSharedPtr vBuf = HardwareBufferManager::getSingleton().
			createVertexBuffer(vertexDecl->getVertexSize(0),vertexData->vertexCount,
			HardwareBuffer::HBU_STATIC_WRITE_ONLY,false);
		/*VertexBufferBinding* binding = vertexData->vertexBufferBinding;
		binding->setBinding(0, vBuf);
		float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD));*/
		// Upload the vertex data to the card
		vBuf->writeData(0,vBuf->getSizeInBytes(),vertices,true);

		/// Set vertex buffer binding so buffer 0 is bound to our vertex buffer
		VertexBufferBinding* bind = wallmesh->sharedVertexData->vertexBufferBinding; 
		bind->setBinding(0, vBuf);

		// allocate index buffer
		pWallVertex->indexData->indexCount = 12;
		pWallVertex->indexData->indexBuffer = HardwareBufferManager::getSingleton().
			createIndexBuffer(HardwareIndexBuffer::IT_16BIT,pWallVertex->indexData->indexCount,
			HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
		HardwareIndexBufferSharedPtr iBuf = pWallVertex->indexData->indexBuffer;
		/*unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD));*/
		iBuf->writeData(0,iBuf->getSizeInBytes(),faces,true);

		//// Set vertex buffer binding so buffer 1 is bound to our index buffer
		//Ogre::IndexBuffer ibind;
		//ibind->setBinding(1, iBuf);

		// Set parameters of the submesh
		pWallVertex->useSharedVertices = true;
		pWallVertex->indexData->indexStart = 0;

		// Set bounding information (for culling)
		wallmesh->_setBounds(Ogre::AxisAlignedBox(-25,-25,-25,25,25,25));
		wallmesh->_setBoundingSphereRadius(25);

		wallmesh->load();
	}

	void createWallMesh2(const Wall3D& wall,String strName)
	{
		MeshPtr wallsMesh = MeshManager::getSingleton().createManual(strName,
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		SubMesh *wallsVertex = wallsMesh->createSubMesh();

		wallsMesh->sharedVertexData = new VertexData();
		VertexData* vertexData = wallsMesh->sharedVertexData;

		// define the vertex format
		VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
		size_t currOffset = 0;
		// positions
		vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION);
		currOffset += VertexElement::getTypeSize(VET_FLOAT3);
		// normals
		vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL);
		currOffset += VertexElement::getTypeSize(VET_FLOAT3);
		// two dimensional texture coordinates
		vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
		currOffset += VertexElement::getTypeSize(VET_FLOAT2);

		// allocate the vertex buffer
		vertexData->vertexCount = 4;
		HardwareVertexBufferSharedPtr vBuf = 
			HardwareBufferManager::getSingleton().createVertexBuffer(
			vertexDecl->getVertexSize(0),vertexData->vertexCount,
			HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY,false);
		VertexBufferBinding* binding = vertexData->vertexBufferBinding;
		binding->setBinding(0, vBuf);
		float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD));

		// allocate index buffer
		wallsVertex->indexData->indexCount = 12;
		wallsVertex->indexData->indexBuffer = 
			HardwareBufferManager::getSingleton().createIndexBuffer(
			HardwareIndexBuffer::IT_16BIT, wallsVertex->indexData->indexCount,
			HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
		HardwareIndexBufferSharedPtr iBuf = wallsVertex->indexData->indexBuffer;
		unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD));

		MyReal height = wall.Height();
		MyVec3 curVec = wall.From();
		MyVec3 prevVec;
		int numWalls = 1;
		int vertIndex=0;


		// fill the first 2 vertices
		*pVertex++ = curVec[0];	
		*pVertex++ = curVec[1];	
		*pVertex++ = curVec[2];	

		// normal
		*pVertex++ = wall.Normal()[0];
		*pVertex++ = wall.Normal()[1];
		*pVertex++ = wall.Normal()[2];

		*pVertex++ = 0;
		*pVertex++ = 0;

		*pVertex++ = curVec[0];
		*pVertex++ = curVec[1]+height;
		*pVertex++ = curVec[2];

		// normal
		*pVertex++ = wall.Normal()[0];
		*pVertex++ = wall.Normal()[1];
		*pVertex++ = wall.Normal()[2];

		*pVertex++ = 0;
		*pVertex++ = 5;

		prevVec = curVec;

		for (int i=0; i<numWalls; i++)
		{
			//Wall3D wall = wstrip.Wall(i);
			curVec = wall.To();

			*pVertex++ = curVec[0];
			*pVertex++ = curVec[1];
			*pVertex++ = curVec[2];

			//normal
			*pVertex++ = wall.Normal()[0];
			*pVertex++ = wall.Normal()[1];
			*pVertex++ = wall.Normal()[2];

			// tex coords
			if(i%2==1)
			{
				*pVertex++ = 0;
				*pVertex++ = 0;
			}
			else
			{
				*pVertex++ = 1;
				*pVertex++ = 0;
			}

			*pVertex++ = curVec[0];
			*pVertex++ = curVec[1]+height;
			*pVertex++ = curVec[2];

			//normal
			*pVertex++ = wall.Normal()[0];
			*pVertex++ = wall.Normal()[1];
			*pVertex++ = wall.Normal()[2];

			// tex coords
			// tex coords
			if(i%2==1)
			{
				*pVertex++ = 0;
				*pVertex++ = 1;
			}
			else
			{
				*pVertex++ = 1;
				*pVertex++ = 5;
			}


			//indices -- each vertex is pointed by 3 indices
			*pIndices++ = vertIndex;
			*pIndices++ = vertIndex+2;
			*pIndices++ = vertIndex+3;

			*pIndices++ = vertIndex;
			*pIndices++ = vertIndex+3;
			*pIndices++ = vertIndex+1;

			*pIndices++ = vertIndex+2;
			*pIndices++ = vertIndex;
			*pIndices++ = vertIndex+1;

			*pIndices++ = vertIndex+2;
			*pIndices++ = vertIndex+1;
			*pIndices++ = vertIndex+3;

			vertIndex += 2;
		}

		// Unlock
		vBuf->unlock();
		iBuf->unlock();

		// Generate face list
		wallsVertex->useSharedVertices = true;
		wallsVertex->indexData->indexStart=0;

		// Set bounding information (for culling)
		wallsMesh->_setBounds(Ogre::AxisAlignedBox(-25,-25,-25,25,25,25));
		wallsMesh->_setBoundingSphereRadius(25);

		wallsMesh->load();
	}


	void createWallsMesh(const std::vector<Wall3D> walls,String strName)
	{
		// if no walls, skip processing
		if(walls.empty())
			return;

		MeshPtr wallsMesh = MeshManager::getSingleton().createManual(strName,
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		SubMesh* wallsVertex = wallsMesh->createSubMesh();

		wallsMesh->sharedVertexData = new VertexData();
		VertexData* vertexData = wallsMesh->sharedVertexData;

		// define the vertex format
		VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
		size_t currOffset = 0;

		// positions
		vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION);
		currOffset += VertexElement::getTypeSize(VET_FLOAT3);
		// normals
		vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL);
		currOffset += VertexElement::getTypeSize(VET_FLOAT3);
		// two dimensional texture coordinates
		vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
		currOffset += VertexElement::getTypeSize(VET_FLOAT2);

		// allocate the vertex buffer
		vertexData->vertexCount = 4;

		// TODO: complete this
	}

	void createWallStripMesh(const Wall3DStrip& wstrip,String strName,
		float htextile=0,float vtextile=0)
	{
		MeshPtr wallsMesh = MeshManager::getSingleton().createManual(strName,
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		SubMesh *wallsVertex = wallsMesh->createSubMesh();

		wallsMesh->sharedVertexData = new VertexData();
		VertexData* vertexData = wallsMesh->sharedVertexData;

		// define the vertex format
		VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
		size_t currOffset = 0;
		// positions
		vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION);
		currOffset += VertexElement::getTypeSize(VET_FLOAT3);
		// normals
		vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL);
		currOffset += VertexElement::getTypeSize(VET_FLOAT3);
		// two dimensional texture coordinates
		vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
		currOffset += VertexElement::getTypeSize(VET_FLOAT2);

		// allocate the vertex buffer
		vertexData->vertexCount = 2*wstrip.NumWalls() + 2;
		HardwareVertexBufferSharedPtr vBuf = 
			HardwareBufferManager::getSingleton().createVertexBuffer(
			vertexDecl->getVertexSize(0),vertexData->vertexCount,
			HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY,false);
		VertexBufferBinding* binding = vertexData->vertexBufferBinding;
		binding->setBinding(0, vBuf);
		float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD));

		// allocate index buffer
		wallsVertex->indexData->indexCount = 12*wstrip.NumWalls();
		wallsVertex->indexData->indexBuffer = 
			HardwareBufferManager::getSingleton().createIndexBuffer(
			HardwareIndexBuffer::IT_16BIT, wallsVertex->indexData->indexCount,
			HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
		HardwareIndexBufferSharedPtr iBuf = wallsVertex->indexData->indexBuffer;
		unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD));

		MyReal height = wstrip.WallsHeight();
		MyVec3 curVec = wstrip.Wall(0).From();
		MyVec3 prevVec;
		int numWalls = wstrip.NumWalls();
		int vertIndex=0;
		float prevhtex;
		float prevvtex;


		// fill the first 2 vertices
		*pVertex++ = curVec[0];	
		*pVertex++ = curVec[1];	
		*pVertex++ = curVec[2];	

		// normal
		*pVertex++ = wstrip.Wall(0).Normal()[0];
		*pVertex++ = wstrip.Wall(0).Normal()[1];
		*pVertex++ = wstrip.Wall(0).Normal()[2];

		*pVertex++ = 0;
		*pVertex++ = 0;

		*pVertex++ = curVec[0];
		*pVertex++ = curVec[1]+height;
		*pVertex++ = curVec[2];

		// normal
		*pVertex++ = wstrip.Wall(0).Normal()[0];
		*pVertex++ = wstrip.Wall(0).Normal()[1];
		*pVertex++ = wstrip.Wall(0).Normal()[2];

		*pVertex++ = 0;
		prevhtex = 0;
		prevvtex = (vtextile==0)?1:(float(height)/vtextile);
		*pVertex++ = prevvtex;

		prevVec = curVec;

		for (int i=0; i<numWalls; i++)
		{
			Wall3D wall = wstrip.Wall(i);
			curVec = wall.To();

			*pVertex++ = curVec[0];
			*pVertex++ = curVec[1];
			*pVertex++ = curVec[2];

			//normal
			*pVertex++ = wall.Normal()[0];
			*pVertex++ = wall.Normal()[1];
			*pVertex++ = wall.Normal()[2];

			if (htextile==0)
			{
				*pVertex++ = ++prevhtex;
			}
			else
			{
				prevhtex += float((curVec-prevVec).length())/htextile;
				*pVertex++ = prevhtex;
			}
			*pVertex++ = 0;

			*pVertex++ = curVec[0];
			*pVertex++ = curVec[1]+height;
			*pVertex++ = curVec[2];

			//normal
			*pVertex++ = wall.Normal()[0];
			*pVertex++ = wall.Normal()[1];
			*pVertex++ = wall.Normal()[2];

			// tex coords
			*pVertex++ = prevhtex;
			if (vtextile==0)
				*pVertex++ = 1;
			else
				*pVertex++ = prevvtex;


			//indices -- each vertex is pointed by 3 indices
			*pIndices++ = vertIndex;
			*pIndices++ = vertIndex+2;
			*pIndices++ = vertIndex+3;

			*pIndices++ = vertIndex;
			*pIndices++ = vertIndex+3;
			*pIndices++ = vertIndex+1;

			*pIndices++ = vertIndex+2;
			*pIndices++ = vertIndex;
			*pIndices++ = vertIndex+1;

			*pIndices++ = vertIndex+2;
			*pIndices++ = vertIndex+1;
			*pIndices++ = vertIndex+3;

			vertIndex += 2;
			prevVec = curVec;
		}

		// Unlock
		vBuf->unlock();
		iBuf->unlock();

		// Generate face list
		wallsVertex->useSharedVertices = true;
		wallsVertex->indexData->indexStart=0;

		wallsMesh->_setBounds( Ogre::AxisAlignedBox(-25,-25,-25,25,25,25));
		wallsMesh->_setBoundingSphereRadius(25);

		wallsMesh->load();
	}


	void createSphere(const std::string& strName, const float r, 
		const int nRings, const int nSegments)
	{
		MeshPtr pSphere = MeshManager::getSingleton().createManual(strName, 
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		SubMesh *pSphereVertex = pSphere->createSubMesh();

		pSphere->sharedVertexData = new VertexData();
		VertexData* vertexData = pSphere->sharedVertexData;

		// define the vertex format
		VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
		size_t currOffset = 0;
		// positions
		vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION);
		currOffset += VertexElement::getTypeSize(VET_FLOAT3);
		// normals
		vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL);
		currOffset += VertexElement::getTypeSize(VET_FLOAT3);
		// two dimensional texture coordinates
		vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
		currOffset += VertexElement::getTypeSize(VET_FLOAT2);

		// allocate the vertex buffer
		vertexData->vertexCount = (nRings + 1) * (nSegments+1);
		HardwareVertexBufferSharedPtr vBuf = 
			HardwareBufferManager::getSingleton().createVertexBuffer(
			vertexDecl->getVertexSize(0), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
		VertexBufferBinding* binding = vertexData->vertexBufferBinding;
		binding->setBinding(0, vBuf);
		float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD));

		// allocate index buffer
		pSphereVertex->indexData->indexCount = 6 * nRings * (nSegments + 1);
		pSphereVertex->indexData->indexBuffer = 
			HardwareBufferManager::getSingleton().createIndexBuffer(
			HardwareIndexBuffer::IT_16BIT, pSphereVertex->indexData->indexCount, 
			HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
		HardwareIndexBufferSharedPtr iBuf = pSphereVertex->indexData->indexBuffer;
		unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD));

		float fDeltaRingAngle = (Ogre::Math::PI / nRings);
		float fDeltaSegAngle = (2 * Ogre::Math::PI / nSegments);
		unsigned short wVerticeIndex = 0 ;

		// Generate the group of rings for the sphere
		for( int ring = 0; ring <= nRings; ring++ ) {
			float r0 = r * sinf (ring * fDeltaRingAngle);
			float y0 = r * cosf (ring * fDeltaRingAngle);

			// Generate the group of segments for the current ring
			for(int seg = 0; seg <= nSegments; seg++) {
				float x0 = r0 * sinf(seg * fDeltaSegAngle);
				float z0 = r0 * cosf(seg * fDeltaSegAngle);

				// Add one vertex to the strip which makes up the sphere
				*pVertex++ = x0;
				*pVertex++ = y0;
				*pVertex++ = z0;

				OgreVec3 vNormal = OgreVec3(x0, y0, z0).normalisedCopy();
				*pVertex++ = vNormal.x;
				*pVertex++ = vNormal.y;
				*pVertex++ = vNormal.z;

				*pVertex++ = (float) seg / (float) nSegments;
				*pVertex++ = (float) ring / (float) nRings;

				if (ring != nRings) {
					// each vertex (except the last) has six indices pointing to it
					*pIndices++ = wVerticeIndex + nSegments + 1;
					*pIndices++ = wVerticeIndex;               
					*pIndices++ = wVerticeIndex + nSegments;
					*pIndices++ = wVerticeIndex + nSegments + 1;
					*pIndices++ = wVerticeIndex + 1;
					*pIndices++ = wVerticeIndex;
					wVerticeIndex ++;
				}
			}; // end for seg
		} // end for ring

		// Unlock
		vBuf->unlock();
		iBuf->unlock();
		// Generate face list
		pSphereVertex->useSharedVertices = true;

		// the original code was missing this line:
		pSphere->_setBounds( Ogre::AxisAlignedBox( OgreVec3(-r, -r, -r), OgreVec3(r, r, r) ), false );
		pSphere->_setBoundingSphereRadius(r);
		// this line makes clear the mesh is loaded (avoids memory leaks)
		pSphere->load();
	}


	void createCube()
	{
		// Create the mesh via the MeshManager
		Ogre::MeshPtr msh = MeshManager::getSingleton().createManual("ColourCube","General");

		// Create one submesh
		SubMesh* sub = msh->createSubMesh();

		const float sqrt13 = 0.577350269f; /* sqrt(1/3) */

		// Define the vertices (8 vertices, each consisting of 2 groups of 3 floats
		const size_t nVertices = 8;
		const size_t vbufCount = 3*2*nVertices;
		float vertices[vbufCount] = {
			-10.0,10.0,-10.0,        //0 position
			-sqrt13,sqrt13,-sqrt13,     //0 normal
			10.0,10.0,-10.0,         //1 position
			sqrt13,sqrt13,-sqrt13,      //1 normal
			10.0,-10.0,-10.0,        //2 position
			sqrt13,-sqrt13,-sqrt13,     //2 normal
			-10.0,-10.0,-10.0,       //3 position
			-sqrt13,-sqrt13,-sqrt13,    //3 normal
			-10.0,10.0,10.0,         //4 position
			-sqrt13,sqrt13,sqrt13,      //4 normal
			10.0,10.0,10.0,          //5 position
			sqrt13,sqrt13,sqrt13,       //5 normal
			10.0,-10.0,10.0,         //6 position
			sqrt13,-sqrt13,sqrt13,      //6 normal
			-10.0,-10.0,10.0,        //7 position
			-sqrt13,-sqrt13,sqrt13,     //7 normal
		};

		RenderSystem* rs = Root::getSingleton().getRenderSystem();
		RGBA colours[nVertices];
		RGBA *pColour = colours;

		// Use render system to convert colour value since colour packing varies
		rs->convertColourValue(ColourValue(1.0,0.0,0.0), pColour++); //0 colour
		rs->convertColourValue(ColourValue(1.0,1.0,0.0), pColour++); //1 colour
		rs->convertColourValue(ColourValue(0.0,1.0,0.0), pColour++); //2 colour
		rs->convertColourValue(ColourValue(0.0,0.0,0.0), pColour++); //3 colour
		rs->convertColourValue(ColourValue(1.0,0.0,1.0), pColour++); //4 colour
		rs->convertColourValue(ColourValue(1.0,1.0,1.0), pColour++); //5 colour
		rs->convertColourValue(ColourValue(0.0,1.0,1.0), pColour++); //6 colour
		rs->convertColourValue(ColourValue(0.0,0.0,1.0), pColour++); //7 colour

		/// Define 12 triangles (two triangles per cube face)
		/// The values in this table refer to vertices in the above table
		const size_t ibufCount = 36;
		unsigned short faces[ibufCount] = {
			0,2,3,
			0,1,2,
			1,6,2,
			1,5,6,
			4,6,5,
			4,7,6,
			0,7,4,
			0,3,7,
			0,5,1,
			0,4,5,
			2,7,3,
			2,6,7
		};

		/// Create vertex data structure for 8 vertices shared between submeshes
		msh->sharedVertexData = new VertexData();
		msh->sharedVertexData->vertexCount = nVertices;

		/// Create declaration (memory format) of vertex data
		VertexDeclaration* decl = msh->sharedVertexData->vertexDeclaration;
		size_t offset = 0;

		// 1st buffer
		decl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
		offset += VertexElement::getTypeSize(VET_FLOAT3);
		decl->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
		offset += VertexElement::getTypeSize(VET_FLOAT3);

		/// Allocate vertex buffer of the requested number of vertices (vertexCount) 
		/// and bytes per vertex (offset)
		HardwareVertexBufferSharedPtr vbuf = 
			HardwareBufferManager::getSingleton().createVertexBuffer(
			offset, msh->sharedVertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
		/// Upload the vertex data to the card
		vbuf->writeData(0, vbuf->getSizeInBytes(), vertices, true);

		/// Set vertex buffer binding so buffer 0 is bound to our vertex buffer
		VertexBufferBinding* bind = msh->sharedVertexData->vertexBufferBinding; 
		bind->setBinding(0, vbuf);

		// 2nd buffer
		offset = 0;
		decl->addElement(1, offset, VET_COLOUR, VES_DIFFUSE);
		offset += VertexElement::getTypeSize(VET_COLOUR);
		/// Allocate vertex buffer of the requested number of vertices (vertexCount) 
		/// and bytes per vertex (offset)
		vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
			offset, msh->sharedVertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
		/// Upload the vertex data to the card
		vbuf->writeData(0, vbuf->getSizeInBytes(), colours, true);

		/// Set vertex buffer binding so buffer 1 is bound to our colour buffer
		bind->setBinding(1, vbuf);

		/// Allocate index buffer of the requested number of vertices (ibufCount) 
		HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton().
			createIndexBuffer(
			HardwareIndexBuffer::IT_16BIT, 
			ibufCount, 
			HardwareBuffer::HBU_STATIC_WRITE_ONLY);

		/// Upload the index data to the card
		ibuf->writeData(0, ibuf->getSizeInBytes(), faces, true);

		/// Set parameters of the submesh
		sub->useSharedVertices = true;
		sub->indexData->indexBuffer = ibuf;
		sub->indexData->indexCount = ibufCount;
		sub->indexData->indexStart = 0;

		/// Set bounding information (for culling)
		msh->_setBounds(Ogre::AxisAlignedBox(-100,-100,-100,100,100,100));
		msh->_setBoundingSphereRadius(Ogre::Math::Sqrt(3*100*100));

		/// Notify Mesh object that it has been loaded
		msh->load();
	}
};

#endif // #ifndef __WallSpiral_h_